pub mod client;
pub mod cmd;

use async_channel::{Receiver, Sender};
use base::{base::VMap, MapSv};
use client::Client;
use serde_json::Value;
use std::time::Instant;
use tracing::{instrument, warn};
use warp::{
    hyper::body::Bytes,
    reject::Rejection,
    reply::{Json, WithStatus},
};

pub use cmd::queue::queue_chunk;

pub type VSend = Sender<Value>;
pub type VRece = Receiver<Value>;

#[instrument(skip_all, name = "s")]
pub async fn do_cmd(
    data: Bytes,
    cmd: String,
    client: &Client,
    tx: VSend,
) -> Result<WithStatus<Json>, Rejection> {
    let val = match base::do_byte(data) {
        Ok(v) => v,
        Err(e) => {
            warn!("error: {:?}", &e);
            return Ok(base::ret_err(&e, None));
        }
    };

    let start = Instant::now();

    match cmd::doit(&val, &cmd, client, tx).await {
        Ok(v) => {
            let duration = start.elapsed();
            warn!("end cmd: {:?}\tdt: {:?}\tpara: {:?}", cmd, duration, val);

            Ok(base::ret_ok(&v))
        }
        Err(e) => {
            let duration = start.elapsed();
            warn!("end cmd: {:?}\tdt: {:?}\tpara: {:?}", cmd, duration, val);
            warn!("error: {:?}", &e);

            Ok(base::ret_err(&e, None))
        }
    }
}

pub fn get_db(data: &MapSv) -> String {
    match data.k_str_trim("db") {
        Some(v) => v.to_string(),
        None => "realtime".to_string(),
    }
}
